import datetime
from typing import Any

import aiofiles
from aiogram import F, types
from aiogram.types import BufferedInputFile
from aiogram_dialog import ChatEvent, Dialog, DialogManager, Window
from aiogram_dialog.widgets.kbd import Button, Cancel, Checkbox
from sqlalchemy.exc import DBAPIError

from app.bot.dialog.dialog_states import OrderDetailsSG
from app.bot.dialog.getters.orders import order_getter
from app.bot.dialog.widgets import LocaleText
from app.bot.handlers.client.orders.authorization_types import (
    start_authorization_change,
)
from app.bot.handlers.client.orders.extend_order import (
    extend_confirmation_window,
    extend_order_window,
    start_order_extend,
)
from app.bot.handlers.client.orders.rotation_period import start_rotation_period_change
from app.bot.handlers.client.proxies.proxy_details import show_ordered_proxies
from app.bot.services.exporters import export_proxies_to_csv
from app.bot.services.locale import Locale
from app.bot.services.loggers import logger
from app.database.enums import OrderPeriod
from app.database.services.allowed_ips import get_allowed_ip_by_order
from app.database.services.orders.common import get_order, set_autorenew
from app.database.services.servers import get_server
from app.database.services.users import get_user


async def export_csv(call: types.CallbackQuery, widget: Any, manager: DialogManager):
    order_id: int = manager.dialog_data.get("order_id")
    locale: Locale = manager.middleware_data.get("locale")
    db_session = manager.middleware_data.get("db_session")

    order = await get_order(db_session, order_id, joined=True)

    if len(order.proxies) > 0:
        server = await get_server(db_session, order.proxies[0].server_id)
        allowed_ip = await get_allowed_ip_by_order(
            db_session, order.user.telegram_id, order_id
        )

        csv = export_proxies_to_csv(order, order.proxies, server, allowed_ip)

        await call.message.answer_document(
            types.BufferedInputFile(
                csv,
                filename=f"Proxies {datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.csv",
            )
        )
    else:
        await call.answer(locale.get("no-proxies-in-order"))


async def send_qr_code(call: types.CallbackQuery, widget: Any, manager: DialogManager):
    order_id: int = manager.dialog_data.get("order_id")
    db_session = manager.middleware_data.get("db_session")
    locale: Locale = manager.middleware_data.get("locale")

    try:
        user = await get_user(db_session, call.from_user.id)
        async with aiofiles.open(
            f"app/media/{user.telegram_id}_{order_id}_vpn_qr.png", "rb"
        ) as f:
            content = await f.read()
        await call.message.answer_photo(
            BufferedInputFile(content, filename="qr_code.png")
        )
    except Exception as e:
        await call.answer(locale.get("error-msg"))
        logger.exception(f"Ошибка при отправке qr кода пользователю: {str(e)}")


async def send_vpn_config(
    call: types.CallbackQuery, widget: Any, manager: DialogManager
):
    order_id: int = manager.dialog_data.get("order_id")
    db_session = manager.middleware_data.get("db_session")
    locale: Locale = manager.middleware_data.get("locale")

    try:
        user = await get_user(db_session, call.from_user.id)
        async with aiofiles.open(
            f"app/media/{user.telegram_id}_{order_id}_vpn.conf", "rb"
        ) as f:
            content = await f.read()
        await call.message.answer_document(
            BufferedInputFile(
                content, filename=f"{call.from_user.id}_{order_id}_vpn.conf"
            )
        )
    except Exception as e:
        await call.answer(locale.get("error-msg"))
        logger.exception(f"Ошибка при отправке qr кода пользователю: {str(e)}")


async def change_autorenew(
    event: ChatEvent, checkbox: Checkbox, manager: DialogManager
):
    db_session = manager.middleware_data.get("db_session")
    locale: Locale = manager.middleware_data.get("locale")
    if manager.start_data:
        order_id: int = manager.start_data.get("order_id")
    else:
        order_id: int = manager.dialog_data.get("order_id")

    auto_renew: bool = not checkbox.widget.default

    try:
        await set_autorenew(db_session, order_id, auto_renew)
        await event.answer(locale.get("order-changed-success"))
        order = await get_order(db_session, order_id)
        if auto_renew:
            if order.type == "subscription":
                await event.message.answer(locale.get("subscription-autorenew-on-msg"))
            else:
                await event.message.answer(locale.get("autorenew-on-msg"))

    except DBAPIError:
        await event.answer(locale.get("error-msg"))


order_details_window = Window(
    LocaleText("order-overview", when=F["order_type"] == "proxy"),
    LocaleText("subscription-overview", when=F["order_type"] == "subcription"),
    LocaleText(
        "order_id", order_id="{order_id}", when=F["order_type"] != "subcription"
    ),
    LocaleText("status", status="{status}"),
    LocaleText(
        "proxies-in-order",
        proxies_amount="{proxies_amount}",
        when=F["order_type"] == "proxy",
    ),
    LocaleText("package-price", package_price="{package_price}$"),
    LocaleText("complete-price", complete_price="{complete_price}$"),
    LocaleText(
        "one-proxy-price",
        one_proxy_price="{one_proxy_price}$",
        when=(F["one_proxy_price"]) & (F["order_type"] == "proxy"),
    ),
    LocaleText(
        "proxy-type",
        proxy_type="{proxy_type_translated}",
        when=F["proxy_type_translated"],
    ),
    LocaleText(
        "proxy-privacy",
        proxy_privacy="{proxy_privacy_translated}",
        when=F["proxy_privacy_translated"],
    ),
    LocaleText(
        "rotation-type", rotation_type="{rotation_type}", when=F["rotation_type"]
    ),
    LocaleText(
        "rotation-period",
        rotation_period="{rotation_period}",
        when=F["rotation_period"],
    ),
    LocaleText(
        "authorization-type",
        authorization_type="{authorization_type}",
        when=F["authorization_type"],
    ),
    LocaleText(
        "authorization-ip",
        authorization_ip="{authorization_ip}",
        when=F["authorization_ip"],
    ),
    LocaleText("proxy-country", country="{country}", when=F["country"]),
    LocaleText(
        "proxy-category", category="{category}", when=F["proxy_privacy"] == "shared"
    ),
    LocaleText("proxy-provider", provider="{provider}", when=F["provider"]),
    LocaleText("proxy-site", site="{site}", when=F["proxy_privacy"] == "shared"),
    LocaleText(
        "authorization-not-set",
        when=(~F["authorization_ip"])
        & (F["proxy_privacy"] == "shared")
        & (F["order_status"] != "archive"),
    ),
    LocaleText("created-at", created_at="{created_at}"),
    LocaleText("selected-period", period="{order_period}", when=F["order_period"]),
    LocaleText(
        "expiring-on",
        expiring_on="{expiring_on}",
        when=(F["order_type"] != "subscription") & (F["expiring_on"]),
    ),
    LocaleText(
        "subscribed-until",
        subscribed_until="{expiring_on}",
        when=F["order_type"] == "subscription",
    ),
    LocaleText("server-time", server_time="{server_time}", when=F["expiring_on"]),
    Button(
        LocaleText("export-to-csv"),
        id="export_csv",
        on_click=export_csv,
        when=(F["proxies_amount"] > 0) & (F["order_status"] != "archive"),
    ),
    Button(
        LocaleText("send-qr-code-btn"),
        id="generate_qr_code",
        on_click=send_qr_code,
        when=(F["order_type"] == "vpn") & (F["order_status"] != "archive"),
    ),
    Button(
        LocaleText("send-config-btn"),
        id="send_vpn_config",
        on_click=send_vpn_config,
        when=(F["order_type"] == "vpn") & (F["order_status"] != "archive"),
    ),
    Button(
        LocaleText("show-ordered-proxies"),
        id="show_ordered_proxies",
        on_click=show_ordered_proxies,
        when=(F["proxies_amount"] > 0) & (F["order_status"] != "archive"),
    ),
    Button(
        LocaleText("extend-order"),
        id="start_order_extend",
        on_click=start_order_extend,
        when=(F["order_status"] != "archive")
        & (F["order_type"] != "subscription")
        & (F["order_type"] != "vpn_router"),
    ),
    Button(
        LocaleText("extend-subscription"),
        id="start_subscription_extend",
        on_click=start_order_extend,
        when=(F["order_status"] != "archive") & (F["order_type"] == "subscription"),
    ),
    Button(
        LocaleText("change-authorization-type"),
        id="start_authorization_type",
        on_click=start_authorization_change,
        when=(F["order_status"] != "archive") & (F["proxies_amount"] > 0),
    ),
    Button(
        LocaleText("change-rotation-time"),
        id="change_rotation_time",
        on_click=start_rotation_period_change,
        when=(F["rotation_type"])
        & (F["order_status"] != "archive")
        & (F["proxies_amount"] > 0),
    ),
    Checkbox(
        LocaleText("autorenew-on"),
        LocaleText("autorenew-off"),
        id="autorenew",
        on_state_changed=change_autorenew,
        when=(F["period"] != OrderPeriod.four_hours)
        & (F["order_status"] != "archive")
        & (F["order_type"] != "vpn_router"),
    ),
    Cancel(LocaleText("back-btn")),
    state=OrderDetailsSG.order_details,
    getter=order_getter,
)

order_details_dialog = Dialog(
    order_details_window,
    extend_order_window,
    extend_confirmation_window,
)
